﻿using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.IO;
using Microsoft.CSharp;

namespace SuperCalculator
{
    /// <summary>
    /// 编译单元。
    /// </summary>
    internal class CompilerUnit
    {
        /// <summary>
        /// 获取或设置编译函数代码时引用的程序集的完整路径的集合。
        /// </summary>
        public static StringCollection ReferenceAssemblyCollection = new StringCollection();
        private static ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();


        /// <summary>
        /// 编译。
        /// </summary>
        /// <param name="source">源代码。</param>
        /// <param name="makeExe">是否生成可执行程序。</param>
        /// <param name="inMemory">是否在内存中生成 (如果true请将, outputAssembly设置为null)。</param>
        /// <param name="dlls">加载的Dll的完整路径。</param>
        /// <param name="outputAssembly">输出程序集的完整路径 (如果inMemory参数为true, 则请使用null)。</param>
        public static CompilerResults Compile(string source, bool makeExe, bool inMemory, string[] dlls, string outputAssembly)
        {
            var parameters = new CompilerParameters();
            //加载dll
            if (dlls != null)
            {
                parameters.ReferencedAssemblies.AddRange(dlls);
            }
            parameters.GenerateExecutable = makeExe;
            parameters.GenerateInMemory = inMemory;
            if (!inMemory)
            {
                parameters.OutputAssembly = outputAssembly;
            }
            var results = compiler.CompileAssemblyFromSource(parameters, source);
            return results;
        }

        /// <summary>
        /// 生成函数Dll。
        /// </summary>
        /// <param name="compileRes">CompilerResult对象。</param>
        /// <returns>成功返回true。</returns>
        public static bool BuildFunctionDll(out CompilerResults compileRes)
        {
            //----------------------------------
            //获取源代码source
            //是所有代码相关文件(.us,.ch,.cf,.ct)的组合
            //----------------------------------
            var source = "";
            source += ReadFile(Function.GetPathOfUsingFile()) +
                ReadFile(Function.GetPathOfClassHeaderFile());
            var dir = new DirectoryInfo(Function.DirectoryOfFunctions);
            var functionFiles = dir.GetFiles("*.cf");
            foreach (var file in functionFiles)
            {
                source += ReadFile(file.FullName);
            }
            source += ReadFile(Function.GetPathOfClassTailFile());

            //添加引用
            var dlls = new string[ReferenceAssemblyCollection.Count];
            ReferenceAssemblyCollection.CopyTo(dlls, 0);

            //输出路径
            var output = Function.GetPathOfNewFunctionDll();
            compileRes = Compile(source, false, false, dlls, output);

            //如果成功生成
            return compileRes.Errors.Count == 0;
        }
        
        public static string ReadFile(string path)
        {
            var sw = new StreamReader(path);
            try
            {
                return sw.ReadToEnd();
            }
            catch
            {
                // ignored
            }
            finally
            {
                sw.Close();
            }
            return "";
        }
    }
}
